﻿using Dotnet.Utils.Utility.Xml;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Net;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Web;
using Dotnet.Utils.Utility.ObjectExtensions.Str;
using Dotnet.Utils.Utility.ObjectExtensions.Number;
using Dotnet.Utils.Utility.ObjectExtensions.To;
using static System.Net.Mime.MediaTypeNames;
using Newtonsoft.Json.Linq;

namespace Dotnet.Utils.Utility.ObjectExtensions.Str
{
    /// <summary>
    /// 字符串String扩展
    /// </summary>
    public static class StringExtension
    {
        private static readonly Regex CRegex_Number = new Regex(@"^[0-9]+$");
        private static readonly Regex CRegex_Word = new Regex(@"^[a-zA-Z]+$");
        private static readonly Regex CRegex_NumberAndString = new Regex(@"(\d+[a-zA-Z])|([a-zA-Z]\d+)");

        #region 以特定字符串间隔的字符串转化为字符串集合

        /// <summary>
        /// 以特定字符间隔的字符串转化为字符串集合
        /// </summary>
        /// <param name="value">需要处理的字符串</param>
        /// <param name="separator">分隔此实例中子字符串</param>
        /// <returns>转化后的字符串集合，如果传入数组为null则返回空集合</returns>
        // ReSharper disable once MemberCanBePrivate.Global
        public static StringCollection ToStringCollection(this string value, string separator)
        {
            var col = new StringCollection();
            if (string.IsNullOrEmpty(separator) || string.IsNullOrEmpty(value) || string.IsNullOrEmpty(value.Trim()))
            {
                return col;
            }
            var index = 0;
            var pos = 0;
            var len = separator.Length;
            while (pos >= 0)
            {
                pos = value.IndexOf(separator, index, StringComparison.CurrentCultureIgnoreCase);
                if (pos >= 0)
                {
                    col.Add(value.Substring(index, pos - index));
                }
                else
                {
                    col.Add(value.Substring(index));
                }
                index = pos + len;
            }
            return col;
        }

        #endregion 以特定字符串间隔的字符串转化为字符串集合

        #region 将字符串中的单词首字母大写或者小写

        /// <summary>
        /// 将字符串中的单词首字母大写或者小写
        /// </summary>
        /// <param name="value">单词</param>
        /// <param name="lower">是否小写? 默认:true</param>
        /// <returns></returns>
        public static string ToTitleUpperCase(this string value, bool lower = true)
        {
            var regex = new Regex(@"\w+");
            return regex.Replace(value,
                delegate (Match m)
                {
                    var str = m.ToString();
                    if (!char.IsLower(str[0])) return str;
                    var header = lower ? char.ToLower(str[0], CultureInfo.CurrentCulture) : char.ToUpper(str[0], CultureInfo.CurrentCulture);
                    return $"{header}{str.Substring(1)}";
                });
        }

        #endregion 将字符串中的单词首字母大写或者小写

        #region 字符串插入指定分隔符

        /// <summary>
        /// 字符串插入指定分隔符
        /// </summary>
        /// <param name="text">字符串</param>
        /// <param name="spacingString">分隔符</param>
        /// <param name="spacingIndex">隔多少个字符插入分隔符</param>
        /// <returns></returns>
        public static string Spacing(this string text, string spacingString, int spacingIndex)
        {
            var sb = new StringBuilder(text);
            for (var i = spacingIndex; i <= sb.Length; i += spacingIndex + 1)
            {
                if (i >= sb.Length) break;
                _ = sb.Insert(i, spacingString);
            }
            return sb.ToString();
        }

        #endregion 字符串插入指定分隔符

        #region 检查一个字符串是否是纯数字构成的，一般用于查询字符串参数的有效性验证

        /// <summary>
        /// 检查一个字符串是否是纯数字构成的,一般用于查询字符串参数的有效性验证
        /// </summary>
        /// <param name="value">需验证的字符串</param>
        /// <returns>是否合法的bool值</returns>
        public static bool IsNumber(this string value) => value.Validate(@"^\d+$");

        #endregion 检查一个字符串是否是纯数字构成的，一般用于查询字符串参数的有效性验证

        #region 验证一个字符串是否符合指定的正则表达式

        /// <summary>
        /// 快速验证一个字符串是否符合指定的正则表达式
        /// </summary>
        /// <param name="value">需验证的字符串</param>
        /// <param name="express">正则表达式的内容</param>
        /// <returns>是否合法的bool值</returns>
        // ReSharper disable once MemberCanBePrivate.Global
        public static bool Validate(this string value, string express)
        {
            if (string.IsNullOrWhiteSpace(value)) return false;
            var myRegex = new Regex(express);
            return myRegex.IsMatch(value);
        }

        #endregion 验证一个字符串是否符合指定的正则表达式

        /// <summary>
        /// 判断字符串中一个字符出现的次数
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="substring">需要查找的字符</param>
        /// <returns></returns>
        public static int StrAppearCount(string str, string substring)
        {
            int count = 0;
            if (string.IsNullOrWhiteSpace(str) || string.IsNullOrWhiteSpace(substring))
                count = 0;
            else if (substring.Length == 1)
                count = str.Count(a => a == substring.ToCharArray()[0]);
            else
                count = str.Contains(substring) ? (str.Length - str.Replace(substring, "").Length) / substring.Length : 0;
            return count;
        }

        /// <summary>
        /// 查询一个字符串中某字符第n次出现的位置
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="substring">需要查找的字符</param>
        /// <param name="count">次数</param>
        /// <returns></returns>
        public static int StrIndex(string str, string substring, int count)
        {
            if (!str.Contains(substring) || //不存在该字符
                count > (str.Length - str.Replace(substring, "").Length) / substring.Length)//查找的次数比出现的次数还大
                return -1;

            int index = 0;
            for (int i = 0; i < count; i++)
                index = str.IndexOf(substring, index) + substring.Length;
            return index - substring.Length;
        }

        /// <summary>
        /// 判断每个字符在字符串中出现的次数，返回元祖
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static List<Tuple<char, int>> OrderedCount(string str)
        {
            return str.GroupBy(x => x).Select(x => Tuple.Create(x.Key, x.Count())).ToList();
        }

        /// <summary>
        /// 字符转ASCII码
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static int StrToASCII(string str)
        {
            //int asc = 'a';    // 把字符直接转换为int类型，即可得到ASCII码值，或者用下面的方式
            // string  character = ((char)60).ToString();//ASCII码转字符：
            return str.Length == 1 ? new ASCIIEncoding().GetBytes(str)[0] : -1;//只能传入一个字符
        }

        /// <summary>
        /// 从字符串的开头得到一个字符串的子串 len参数不能大于给定字符串的长度
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static string Left(this string str, int len) => str.Length < len ? str : str.Substring(0, len);
        public static string Left2(this string value, int length)
        {
            return value != null && value.Length > length ? value.Substring(0, length) : value;
        }


        /// <summary>
        /// 从字符串的末尾得到一个字符串的子串 len参数不能大于给定字符串的长度
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static string Right(this string str, int len) => str.Length < len ? str : str.Substring(str.Length - len, len);

        /// <summary>
        /// len参数大于给定字符串是返回原字符串
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string MaxLeft(this string str, int len) => str.Length < len ? str : str.Substring(0, len);

        /// <summary>
        /// 从字符串的末尾得到一个字符串的子串
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string MaxRight(this string str, int len) => str.Length < len ? str : str.Substring(str.Length - len, len);

        /// <summary>
        /// 字符串掩码[俗称:脱敏]
        /// </summary>
        /// <param name="value">字符串</param>
        /// <param name="mask">掩码符</param>
        /// <returns></returns>
        public static string Mask(this string value, char mask = '*')
        {
            if (string.IsNullOrWhiteSpace(value.Trim())) return value;
            value = value.Trim();
            var masks = mask.ToString().PadLeft(4, mask);

            var len = value.Length;
            if (len >= 11)
            {
                return Regex.Replace(value, "(.{3}).*(.{4})", "$1" + masks + "$2");
            }
            else if (len == 10)
            {
                return Regex.Replace(value, "(.{3}).*(.{3})", "$1" + masks + "$2");
            }
            else if (len == 9)
            {
                return Regex.Replace(value, "(.{2}).*(.{3})", "$1" + masks + "$2");
            }
            else if (len == 8)
            {
                return Regex.Replace(value, "(.{2}).*(.{2})", "$1" + masks + "$2");
            }
            else if (len == 7)
            {
                return Regex.Replace(value, "(.{1}).*(.{2})", "$1" + masks + "$2");
            }
            else if (len == 6)
            {
                return Regex.Replace(value, "(.{1}).*(.{1})", "$1" + masks + "$2");
            }
            else
            {
                return Regex.Replace(value, "(.{1}).*", "$1" + masks);
            }
        }

        /// <summary>
        /// 根据正则替换
        /// </summary>
        /// <param name="input"></param>
        /// <param name="regex">正则表达式</param>
        /// <param name="replacement">新内容</param>
        /// <returns></returns>
        public static string Replace(this string input, Regex regex, string replacement) => regex.Replace(input, replacement);

        /// <summary>
        /// 截断一个字符串,并在末尾添加一个后缀
        /// </summary>
        /// <param name="value">原始字符串</param>
        /// <param name="maxLength">最大长度(添加后缀后的长度)</param>
        /// <param name="suffix">后缀,默认: ...</param>
        /// <returns></returns>
        public static string Truncate(this string value, int maxLength, string suffix = "...") =>
             string.IsNullOrEmpty(value) || value.Length <= maxLength
                ? value : maxLength - suffix.Length <= 0 ?
            suffix.Substring(0, maxLength) : $"{value.Substring(0, maxLength - suffix.Length)}{suffix}";

        /// <summary>
        /// 取中文简拼
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns>转化后的字符串</returns>
        public static string GetChineseSpell(this string source)
        {
            int len = source.Length;
            string s = string.Empty;
            for (int i = 0; i < len; i++)
                s += GetSpell(source.Substring(i, 1));
            return s;
        }

        private static string GetSpell(string c)
        {
            byte[] ary = Encoding.Default.GetBytes(c);
            if (ary.Length > 1)
            {
                int area = ary[0];
                int pos = ary[1];
                int code = (area << 8) + pos;
                int[] areacode = { 45217, 45253, 45761, 46318, 46826, 47010, 47297, 47614, 48119, 48119, 49062, 49324, 49896, 50371, 50614, 50622, 50906, 51387, 51446, 52218, 52698, 52698, 52698, 52980, 53689, 54481 };
                for (int i = 0; i < 26; i++)
                {
                    int max = 55290;
                    if (i != 25)
                        max = areacode[i + 1];
                    if (areacode[i] <= code && code < max)
                        return Encoding.Default.GetString(new[] { (byte)(65 + i) });
                }
                return string.Empty;
            }
            return c;
        }

        /// <summary>
        /// 是否为纯数字字符串(0..9)
        /// </summary>
        /// <param name="source">源字符串</param>
        public static bool IsOnlyNumber(this string source)
        {
            return CRegex_Number.Match(source).Success;
        }

        /// <summary>
        /// 是否为数字+字母字符串(0..9,a..z,A..Z)
        /// </summary>
        /// <param name="source">源字符串</param>
        public static bool IsNumberAndString(this string source)
        {
            return CRegex_NumberAndString.Match(source).Success;
        }

        /// <summary>
        /// 是否为纯字母字符串(a..z,A..Z)
        /// </summary>
        /// <param name="source">源字符串</param>
        public static bool IsOnlyWord(this string source)
        {
            return CRegex_Word.Match(source).Success;
        }

        /// <summary>
        /// 比较字符串是否相同(不区分大小写)
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="s">比较的字符串</param>
        /// <returns>是否相同</returns>
        public static bool SameText(this string source, string s)
        {
            return string.Compare(source, s, true) == 0;
        }

        /// <summary>
        /// 生成引用字符串,abc --> "abc"
        /// </summary>
        public static string ToQuote(this string source, char quoteChar)
        {
            return StringHelper.ToQuote(source, quoteChar);
        }

        /// <summary>
        /// 生成引用字符串，使用<c>'</c>作为引用字符
        /// </summary>
        public static string ToQuoteSingle(this string source)
        {
            return StringHelper.ToQuoteSingle(source);
        }

        /// <summary>
        /// 解析引用字符串
        /// </summary>
        public static string FromQuote(this string source, char quoteChar)
        {
            return StringHelper.FromQuote(source, quoteChar);
        }

        /// <summary>
        /// 解析引用字符串，使用<c>'</c>作为引用字符
        /// </summary>
        public static string FromQuoteSingle(this string source)
        {
            return StringHelper.FromQuoteSingle(source);
        }

        /// <summary>
        /// 是否全部由0-9数字的数字组成
        /// </summary>
        public static bool IsDigit(this string source)
        {
            return StringHelper.IsDigit(source);
        }

        /// <summary>
        /// 是否为有效的整数
        /// </summary>
        public static bool IsInt32(this string source)
        {
            return StringHelper.IsInt(source);
        }

        /// <summary>
        /// 是否为有效的整数
        /// </summary>
        public static bool IsInt64(this string source)
        {
            return long.TryParse(source, out long value);
        }

        /// <summary>
        /// 是否为有效的浮点数
        /// </summary>
        public static bool IsFloat(this string source)
        {
            return StringHelper.IsFloat(source);
        }

        /// <summary>
        /// 是否为有效的浮点数
        /// </summary>
        public static bool IsDouble(this string source)
        {
            return StringHelper.IsDouble(source);
        }

        /// <summary>
        /// 是否为有效的日期
        /// </summary>
        public static bool IsDateTime(this string source)
        {
            return StringHelper.IsDateTime(source);
        }

        /// <summary>
        /// 源字符串是分全部由 charArray 的字符组成
        /// </summary>
        public static bool IsCustomChars(this string source, char[] charArray)
        {
            return StringHelper.IsCustomChars(source, charArray);
        }

        /// <summary>
        /// 是否含有中文字符
        /// </summary>
        public static bool IsIncUnicodeChar(this string source)
        {
            return StringHelper.IsIncUnicodeChar(source);
        }

        /// <summary>
        /// 比较2个字符串是否相同
        /// </summary>
        public static bool IsSame(this string source, string target, bool ignoreCase)
        {
            return StringHelper.IsSame(source, target, ignoreCase);
        }

        /// <summary>
        /// 比较2个字符串是否相同,不区分大小写
        /// </summary>
        public static bool IsSame(this string source, string target)
        {
            return StringHelper.IsSame(source, target, true);
        }

        /// <summary>
        /// 字符串是否在一个字符串数组中
        /// </summary>
        public static bool IsOneOf(this string source, string[] strArr, bool ignoreCase)
        {
            return StringHelper.IsOneOf(source, strArr, ignoreCase);
        }

        /// <summary>
        /// 替换字符
        /// </summary>
        public static string Replace(this string source, string oldValue, string newValue, bool ignoreCase)
        {
            return StringHelper.Replace(source, oldValue, newValue, ignoreCase);
        }

        /// <summary>
        /// 替换字符
        /// </summary>
        public static string Replace(this string source, string oldValue, string newValue, int startIndex, int count, bool ignoreCase)
        {
            return StringHelper.Replace(source, oldValue, newValue, startIndex, count, ignoreCase);
        }

        /// <summary>
        /// 数字按Step的步进递增
        /// 0==>9  9==>0
        /// A==>Z  Z==>A
        /// a==>Z  z==>A
        /// 其他字符跳过
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="step">步进</param>
        /// <returns>转化后的字符串</returns>
        public static string IncLetterOrDigit(this string source, int step)
        {
            return StringHelper.IncLetterOrDigit(source, step);
        }

        /// <summary>
        /// 数字按Step的步进递增
        /// 0==>9  9==>A  A==>Z  Z==>0
        /// a==>Z
        /// z==>0
        /// 其他字符跳过
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <param name="step">步进</param>
        /// <returns>转化后的字符串</returns>
        public static string IncLetterAndDigit(this string source, int step)
        {
            return StringHelper.IncLetterAndDigit(source, step);
        }

        /// <summary>
        /// 直接格式化字符串
        /// </summary>
        public static string FormatMe(this string source, params object[] args)
        {
            return string.Format(source, args);
        }

        /// <summary>
        /// 统计 find  在 source 中的个数
        /// </summary>
        public static int IndexOfCount(this string source, string find, bool ignoreCase)
        {
            return StringHelper.IndexOfCount(source, find, ignoreCase);
        }

        /// <summary>
        /// 指示指定的 System.String 对象是 null 还是 System.String.Empty 字符串。
        /// </summary>
        public static bool IsNullOrEmpty(this string source)
        {
            return string.IsNullOrEmpty(source);
        }

        /// <summary>
        /// 取左边字符串
        /// </summary>
        public static string LeftString(this string source, int count)
        {
            if (string.IsNullOrEmpty(source))
                return string.Empty;
            int len = source.Length;
            return len > count ? source.Substring(0, count) : source;
        }

        /// <summary>
        /// 取左边字符串
        /// </summary>
        public static string RightString(this string source, int count)
        {
            if (string.IsNullOrEmpty(source))
                return string.Empty;
            int len = source.Length;
            if (len > count)
                return source.Substring(len - count, count);
            return source;
        }

        public static string Md5(this string source)
        {
            if (source == "")
            {
                return "";
            }
            else
            {
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] bytes = Encoding.UTF8.GetBytes(source);
                bytes = md5.ComputeHash(bytes);
                md5.Clear();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < bytes.Length; i++)
                    sb.Append(bytes[i].ToString("x2"));
                return sb.ToString();
            }
        }

        /// <summary>
        /// 转换为时间
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static DateTime ToDateTime2(this string str)
        {
            return Convert.ToDateTime(str);
        }

        /// <summary>
        /// 转为int
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int ToInt(this string str)
        {
            return Convert.ToInt32(str);
        }

        /// <summary>
        /// 转为short
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static long ToLong(this string str)
        {
            return Convert.ToInt64(str);
        }

        /// <summary>
        /// 转为int
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static short ToShort(this string str)
        {
            return Convert.ToInt16(str);
        }

        /// <summary>
        /// sha算法
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string SHA1(this string str)
        {
            //byte[] b = Encoding.Default.GetBytes(str);
            //byte[] sha = System.Security.Cryptography.SHA1.Create().ComputeHash(b);
            //return BitConverter.ToString(sha).Replace("-","") ;

            SHA1 sha1 = new SHA1CryptoServiceProvider();
            byte[] bytes_sha1_in = Encoding.Default.GetBytes(str);
            byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in);
            string str_sha1_out = BitConverter.ToString(bytes_sha1_out);
            str_sha1_out = str_sha1_out.Replace("-", "");
            return str_sha1_out;
        }

        /// <summary>
        /// 将JSON字符串符合条件的字段,按照最大长度截断
        /// </summary>
        /// <param name="json"></param>
        /// <param name="predicate">筛选字段名</param>
        /// <param name="maxLength">最大长度(添加后缀后的长度)</param>
        /// <param name="suffix">后缀,默认: ...</param>
        /// <returns></returns>
        public static string TruncateJson(this string json, Func<string, bool> predicate, int maxLength, string suffix = "...")
        {
            var doc = JObject.Parse(json);

            var sb = new StringBuilder();
            sb.Append('{');
            foreach (var property in doc.Properties())
            {
                var name = property.Name;
                var value = property.Value.ToString();
                if (predicate(name) && value.Length > maxLength)
                {
                    value = value.Truncate(maxLength - suffix.Length, suffix);
                }
                sb.Append($"\"{name}\":\"{value}\",");
            }
            sb.Length--;
            sb.Append('}');
            return sb.ToString();
        }

        /// <summary>
        /// 将字符串集合链接起来
        /// </summary>
        /// <param name="strs"></param>
        /// <param name="separate">分隔符</param>
        /// <param name="removeEmpty">是否移除空白字符</param>
        /// <returns></returns>
        public static string Join(this IEnumerable<string> strs, string separate = ", ", bool removeEmpty = false) => string.Join(separate, removeEmpty ? strs.Where(s => !string.IsNullOrEmpty(s)) : strs);

        /// <summary>
        /// 转成非null
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string AsNotNull(this string s) => string.IsNullOrEmpty(s) ? "" : s;

        /// <summary>
        /// 转成非null
        /// </summary>
        /// <param name="s"></param>
        /// <param name="value">为空时的替换值</param>
        /// <returns></returns>
        public static string IfNullOrEmpty(this string s, string value) => string.IsNullOrEmpty(s) ? value : s;

        /// <summary>
        /// 转成非null
        /// </summary>
        /// <param name="s"></param>
        /// <param name="valueFactory">为空时的替换值函数</param>
        /// <returns></returns>
        public static string IfNullOrEmpty(this string s, Func<string> valueFactory) => string.IsNullOrEmpty(s) ? valueFactory() : s;

        #region 校验手机号码的正确性

        /// <summary>
        /// 匹配手机号码
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <returns>是否匹配成功</returns>
        public static bool MatchPhoneNumber(this string s) => !string.IsNullOrEmpty(s) && s[0] == '1' && (s[1] > '2' || s[1] <= '9');

        #endregion 校验手机号码的正确性

        #region 转化成人民币汉字形式

        /// <summary>
        /// 转换人民币大小金额 .
        /// </summary>
        /// <param name="numStr">金额</param>
        /// <returns>返回大写形式</returns>
        public static string ToRMB(this string numStr) => numStr.ConvertTo<decimal>().ToRMB();

        #endregion 转化成人民币汉字形式

        #region 字符串转为日期

        /// <summary>
        /// 将格式化日期串转化为相应的日期
        /// （比如2004/05/06，2004-05-06 12:00:03，12:23:33.333等）
        /// </summary>
        /// <param name="value">日期格式化串</param>
        /// <returns>转换后的日期，对于不能转化的返回DateTime.MinValue</returns>
        public static DateTime ToDateTime(this string value) => value.ToDateTime(DateTime.MinValue);

        /// <summary>
        /// 将格式化日期串转化为相应的日期
        /// （比如2004/05/06，2004-05-06 12:00:03，12:23:33.333等）
        /// </summary>
        /// <param name="value">日期格式化串</param>
        /// <param name="defaultValue">当为空或错误时的返回日期</param>
        /// <returns>转换后的日期</returns>
        // ReSharper disable once MemberCanBePrivate.Global
        public static DateTime ToDateTime(this string value, DateTime defaultValue)
        {
            var result = DateTime.MinValue;
            return string.IsNullOrEmpty(value) || DateTime.TryParse(value, out result) ? result : defaultValue;
        }

        /// <summary>
        /// 从字符串获取DateTime?,支持的字符串格式:'2020/10/01,2020-10-01,20201001,2020.10.01'
        /// </summary>
        /// <param name="value"></param>
        /// <param name="force">true:当无法转换成功时抛出异常.false:当无法转化成功时返回null</param>
        public static DateTime? ToDateTime(this string value, bool force)
        {
            value = Regex.Replace(value, @"[^a-zA-Z0-9]", "-");

            if (value.Split('-').Length == 1 && value.Length == 8)
            {
                value = string.Join("-", value.Substring(0, 4), value.Substring(4, 2), value.Substring(6, 2));
            }
            DateTime date;
            if (DateTime.TryParse(value, out date))
            {
                return date;
            }
            else
            {
                if (force)
                {
                    throw new Exception("string format is not correct, must like:2020/10/01,2020-10-01,20201001,2020.10.01");
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// 将字符串转化为固定日期格式字符串,如:20180506 --> 2018-05-06
        /// </summary>
        /// <exception cref="FormatException"></exception>
        public static string ToDateTimeFormat(this string value, bool force = true)
        {
            var sb = new StringBuilder(value);
            sb.Replace("/", "-").Replace(".", "-").Replace("。", "-").Replace(",", "-").Replace(" ", "-").Replace("|", "-");
            if (sb.ToString().Split('-').Length == 1 && sb.Length == 8) sb = sb.Insert(4, "-").Insert(7, "-");
            return DateTime.TryParse(sb.ToString(), out _)
                       ? sb.ToString()
                       : force
                           ? throw new ArgumentException("string format is not correct,must like:2020/10/01,2020-10-01,20201001,2020.10.01")
                           : string.Empty;
        }

        /// <summary>
        /// 获取某个日期串的DateOnly
        /// </summary>
        /// <param name="value">格式如: 2022-02-28</param>
        /// <returns></returns>
        public static DateOnly ToDateOnly(this string value) => DateOnly.FromDateTime(value.ToDateTime());

        /// <summary>
        /// 获取某个时间串的TimeOnly
        /// </summary>
        /// <param name="value">格式如: 23:20:10</param>
        /// <returns></returns>
        public static TimeOnly ToTimeOnly(this string value) => TimeOnly.FromDateTime($"{DateTime.Now:yyyy-MM-dd} {value}".ToDateTime());



        #endregion 字符串转为日期

        #region 将字符串转为整数,数组,内存流,GUID(GUID需要字符串本身为GUID格式)

        /// <summary>
        /// 将字符串转化为内存字节流
        /// </summary>
        /// <param name="value">需转换的字符串</param>
        /// <param name="encoding">编码类型</param>
        /// <returns>字节流</returns>
        // ReSharper disable once MemberCanBePrivate.Global
        public static MemoryStream ToStream(this string value, Encoding encoding)
        {
            using (var mStream = new MemoryStream())
            {
                var data = encoding.GetBytes(value);
                mStream.Write(data, 0, data.Length);
                mStream.Position = 0;
                return mStream;
            }
        }

        /// <summary>
        /// 将字符串转化为内存字节流
        /// </summary>
        /// <param name="value">需转换的字符串</param>
        /// <param name="charset">字符集代码</param>
        /// <returns>字节流</returns>
        public static MemoryStream ToStream(this string value, string charset) => value.ToStream(Encoding.GetEncoding(charset));

        /// <summary>
        /// 将字符串以默认编码转化为内存字节流
        /// </summary>
        /// <param name="value">需转换的字符串</param>
        /// <returns>字节流</returns>
        public static MemoryStream ToStream(this string value) => value.ToStream(Encoding.UTF8);

        /// <summary>
        /// 将字符串拆分为数组
        /// </summary>
        /// <param name="value">需转换的字符串</param>
        /// <param name="separator">分割符</param>
        /// <returns>字符串数组</returns>
        public static string[] Split(this string value, string separator)
        {
            var collection = value.ToStringCollection(separator);
            var vs = new string[collection.Count];
            collection.CopyTo(vs, 0);
            return vs;
        }

        /// <summary>
        /// 转换为Guid类型
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static Guid ToGuid(this string str) => Guid.TryParse(str, out var guid) ? guid : Guid.Empty;

        #endregion 将字符串转为整数,数组,内存流,GUID(GUID需要字符串本身为GUID格式)

        #region Base64-String互转

        /// <summary>
        /// 将字符串转换成Base64字符串
        /// </summary>
        /// <param name="value">字符串</param>
        /// <returns></returns>
        public static string ToBase64(this string value) => Convert.ToBase64String(Encoding.UTF8.GetBytes(value));

        /// <summary>
        /// 将Base64字符转成String
        /// </summary>
        /// <param name="value">Base64字符串</param>
        /// <returns></returns>
        public static string Base64ToString(this string value) => Encoding.UTF8.GetString(Convert.FromBase64String(value));

        #endregion Base64-String互转

        #region 半角全角相互转换

        /// <summary>
        /// 转全角的函数(SBC case)
        /// </summary>
        /// <param name="input">需要转换的字符串</param>
        /// <returns>转换为全角的字符串</returns>
        public static string ToSbc(this string input)
        {
            //半角转全角：
            var c = input.ToCharArray();
            for (var i = 0; i < c.Length; i++)
            {
                if (c[i] == 0x20)
                {
                    c[i] = (char)0x3000;
                    continue;
                }
                if (c[i] < 0x7F) c[i] = (char)(c[i] + 0xFEE0);
            }
            return new string(c);
        }

        /// <summary>
        /// 转半角的函数(SBC case)
        /// </summary>
        /// <param name="input">需要转换的字符串</param>
        /// <returns>转换为半角的字符串</returns>
        public static string ToDbc(this string input)
        {
            var c = input.ToCharArray();
            for (var i = 0; i < c.Length; i++)
            {
                if (c[i] == 0x3000)
                {
                    c[i] = (char)0x20;
                    continue;
                }
                if (c[i] > (char)0xFF00 && c[i] < (char)0xFF5F)
                {
                    c[i] = (char)(c[i] - 0xFEE0);
                }
            }
            return new string(c);
        }

        #endregion 半角全角相互转换

        #region 字符串反转

        /// <summary>
        /// 使用指针的方式反转字符串,该函数会修改原字符串.
        /// </summary>
        /// <param name="value">待反转字符串</param>
        /// <returns>反转后的结果</returns>
        public static string Reverse(this string value)
        {
            if (value == null) return null;
            char[] charArray = value.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }

        /// <summary>
        /// 使用StringBuilder和索引器的方式反转字符串,该函数不会修改原字符串
        /// </summary>
        /// <param name="value">待反转字符串</param>
        /// <returns>反转后的结果</returns>
        public static string ReverseByStringBuilder(this string value)
        {
            var sb = new StringBuilder(value.Length);
            for (var i = value.Length; i > 0;)
            {
                _ = sb.Append(value[--i]);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 使用Array.Reverse()的方式反转字符串,该函数不会修改原字符串
        /// </summary>
        /// <param name="value">待反转字符串</param>
        /// <returns>反转后的结果</returns>
        public static string ReverseByArray(this string value)
        {
            var arr = value.ToCharArray();
            Array.Reverse(arr);
            return new string(arr);
        }

        #endregion 字符串反转

        #region 检测字符串中是否包含列表中的关键词

        /// <summary>
        /// 检测字符串中是否包含列表中的关键词(快速匹配)
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="keys">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool Contains(this string s, IEnumerable<string> keys, bool ignoreCase = true)
        {
            ICollection<string> array = keys as ICollection<string>;
            if (array == null)
            {
                array = keys.ToArray();
            }
            return array.Count != 0 && !string.IsNullOrEmpty(s) && (ignoreCase ? array.Any(item => s.IndexOf(item, StringComparison.InvariantCultureIgnoreCase) >= 0) : array.Any(s.Contains));
        }

        /// <summary>
        /// 检测字符串中是否包含列表中的关键词(安全匹配)
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="keys">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool ContainsSafety(this string s, IEnumerable<string> keys, bool ignoreCase = true)
        {
            ICollection<string> array = keys as ICollection<string>;
            if (array == null)
            {
                array = keys.ToArray();
            }
            if (array.Count == 0 || string.IsNullOrEmpty(s))
                return false;
            var flag = false;
            if (ignoreCase)
            {
                foreach (var item in array)
                {
                    if (s.Contains(item)) flag = true;
                }
            }
            else
            {
                foreach (var item in array)
                {
                    if (s?.IndexOf(item, StringComparison.InvariantCultureIgnoreCase) >= 0) flag = true;
                }
            }
            return flag;
        }

        /// <summary>
        /// 检测字符串中是否以列表中的关键词结尾
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="keys">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool EndsWith(this string s, IEnumerable<string> keys, bool ignoreCase = true)
        {
            ICollection<string> array = keys as ICollection<string>;
            if (array == null)
            {
                array = keys.ToArray();
            }
            if (array.Count == 0 || string.IsNullOrEmpty(s))
                return false;
            var pattern = $"({array.Select(Regex.Escape).Join("|")})$";
            return ignoreCase ? Regex.IsMatch(s, pattern, RegexOptions.IgnoreCase) : Regex.IsMatch(s, pattern);
        }

        /// <summary>
        /// 检测字符串中是否以列表中的关键词开始
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="keys">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool StartsWith(this string s, IEnumerable<string> keys, bool ignoreCase = true)
        {
            ICollection<string> array = keys as ICollection<string>;
            if (array == null)
            {
                array = keys.ToArray();
            }
            if (array.Count == 0 || string.IsNullOrEmpty(s))
                return false;
            var pattern = $"^({array.Select(Regex.Escape).Join("|")})";
            return ignoreCase ? Regex.IsMatch(s, pattern, RegexOptions.IgnoreCase) : Regex.IsMatch(s, pattern);
        }

        /// <summary>
        /// 检测字符串中是否包含列表中的关键词
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="regex">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool RegexMatch(this string s, string regex, bool ignoreCase = true) => !string.IsNullOrEmpty(regex) && !string.IsNullOrEmpty(s) && (ignoreCase ? Regex.IsMatch(s, regex, RegexOptions.IgnoreCase) : Regex.IsMatch(s, regex));

        /// <summary>
        /// 检测字符串中是否包含列表中的关键词
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="regex">关键词列表</param>
        /// <returns></returns>
        public static bool RegexMatch(this string s, Regex regex) => !string.IsNullOrEmpty(s) && regex.IsMatch(s);

        #endregion 检测字符串中是否包含列表中的关键词

        public static List<Guid> ToGuidList(this string input)
        {
            return ConvertUtil.ToList<Guid>(input);
        }

        public static List<T> ToList<T>(this string input)
        {
            return ConvertUtil.ToList<T>(input);
        }

        public static byte[] ToBytes(this string input)
        {
            return ConvertUtil.ToBytes(input);
        }

        public static byte[] ToBytes(this string input, Encoding encoding)
        {
            return ConvertUtil.ToBytes(input, encoding);
        }

        public static T FromXml<T>(this string @this)
        {
            return XmlUtil.Deserialize<T>(@this);
        }

        public static string Truncate(this string text, int maxLength)
        {
            string result;
            if (maxLength <= 0)
            {
                result = text;
            }
            else
            {
                int num = maxLength - "...".Length;
                if (num <= 0)
                {
                    result = text;
                }
                else if (text == null || text.Length <= maxLength)
                {
                    result = text;
                }
                else
                {
                    string text2 = text.Substring(0, num);
                    text2 = text2.TrimEnd(new char[0]);
                    text2 += "...";
                    result = text2;
                }
            }
            return result;
        }

        public static bool IsValidEmail(this string obj)
        {
            return Regex.IsMatch(obj, "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z0-9]{1,30})(\\]?)$");
        }

        public static bool IsValidIP(this string obj)
        {
            return Regex.IsMatch(obj, "^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$");
        }

        public static string UrlEncode(this string str)
        {
            return HttpUtility.UrlEncode(str);
        }

        public static string UrlDecode(this string str)
        {
            return HttpUtility.UrlDecode(str);
        }

        public static string DecodeBase64(this string str)
        {
            return Encoding.UTF8.GetString(Convert.FromBase64String(str));
        }

        public static string EncodeBase64(this string str)
        {
            return Convert.ToBase64String(Encoding.UTF8.GetBytes(str));
        }

        public static bool EqualsIgnoreCase(this string str, string comparedString)
        {
            return str.Equals(comparedString, StringComparison.OrdinalIgnoreCase);
        }

        public static bool ContainsIgnoreCase(this string str, string value)
        {
            return str.IndexOf(value, StringComparison.OrdinalIgnoreCase) != -1;
        }

        public static string EscapeXml(this string str)
        {
            return SecurityElement.Escape(str);
        }

        public static bool StartsWithIgnoreCase(this string str, string value)
        {
            return str.StartsWith(value, StringComparison.OrdinalIgnoreCase);
        }

        /// <summary>
        /// Converts a byte[] to string without BOM (byte order mark).
        /// </summary>
        /// <param name="bytes">The byte[] to be converted to string</param>
        /// <param name="encoding">The encoding to get string. Default is UTF8</param>
        /// <returns></returns>
        public static string ConvertFromBytesWithoutBom(byte[] bytes, Encoding encoding = null)
        {
            if (bytes == null)
            {
                return null;
            }

            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }

            var hasBom = bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF;

            if (hasBom)
            {
                return encoding.GetString(bytes, 3, bytes.Length - 3);
            }
            else
            {
                return encoding.GetString(bytes);
            }
        }

        /// <summary>
        /// 获取字母大小写的所有组合
        /// 參考文档：https://www.geeksforgeeks.org/dsa/permute-string-changing-case/
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static List<string> LetterPermuteList(string input)
        {
            List<string> list = new List<string>();
            for (int i = 0; i < 1 << input.Length; i++)
            {
                char[] combination = input.ToLower().ToCharArray();
                for (int j = 0; j < input.Length; j++)
                    if ((i >> j & 1) == 1)
                        combination[j] = (char)(combination[j] - 32);
                list.Add(string.Concat(combination));
            }
            return list;
        }

        public static bool ExistsIn(string target, string keyword)
        {
            if (string.IsNullOrEmpty(target)) return false;
            return target.Contains(keyword);
        }


        /// <summary>
        /// 生成随机字符(数字+字母)
        /// </summary>
        /// <param name="length">字符长度</param>
        /// <returns>随机字符组成的字符串</returns>
        public static string GetRandomStr(int length)
        {
            char[] arrChar ={
    '0','1','2','3','4','5','6','7','8','9',
    'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
    };

            StringBuilder sb = new StringBuilder();
            int arrCharLength = arrChar.Length;
            Random rd = new Random();
            for (int i = 0; i < length; i++)
            {
                sb.Append(arrChar[rd.Next(arrCharLength)]);
            }
            return sb.ToString();
        }


        /// <summary>
        /// 生成随机字符
        /// </summary>
        /// <param name="length">字符长度</param>
        /// <param name="number">是否包含数字</param>
        /// <param name="lower">是否包含小写字母</param>
        /// <param name="upper">是否包含大写字母</param>
        /// <param name="symbol">是否包含特殊字母</param>
        /// <returns>随机字符组成的字符串</returns>
        public static string GetRandomString(int length, bool number = true, bool lower = true, bool upper = true, bool symbol = false)
        {
            char[] numberChars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
            char[] lowerChars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
            char[] upperChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
            //反斜杠是转义符,\\\" 代表 \"
            char[] symbolChars = "\\\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~".ToArray();

            IEnumerable<char> charList = Enumerable.Empty<char>();
            if (number) charList = charList.Union(numberChars);
            if (lower) charList = charList.Union(lowerChars);
            if (upper) charList = charList.Union(upperChars);
            if (symbol) charList = charList.Union(symbolChars);

            var arrChar = charList.ToArray();
            int arrCharLength = arrChar.Length;
            if (arrCharLength == 0)
            {
                return string.Empty;
            }

            StringBuilder sb = new StringBuilder();
            Random rd = new Random();
            for (int i = 0; i < length; i++)
            {
                sb.Append(arrChar[rd.Next(arrCharLength)]);
            }
            return sb.ToString();
        }



        /// <summary>
        /// 获取本地IP地址
        /// </summary>
        private static string GetLocalIPAddress()
        {
            var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
            foreach (var network in networkInterfaces)
            {
                if (network.OperationalStatus != OperationalStatus.Up)
                    continue;
                var properties = network.GetIPProperties();
                if (properties.GatewayAddresses.Count == 0)
                    continue;

                foreach (var address in properties.UnicastAddresses)
                {
                    if (address.Address.AddressFamily != AddressFamily.InterNetwork)
                        continue;
                    if (IPAddress.IsLoopback(address.Address))
                        continue;
                    return address.Address.ToString();
                }
            }
            return "127.0.0.1";
        }

        /// <summary>
        /// 获取本地IP地址2
        /// </summary>
        private static string GetLocalIPAddress2()
        {
            var result = Dns.GetHostEntry(Dns.GetHostName())
                 .AddressList.FirstOrDefault(address =>
                 address.AddressFamily == AddressFamily.InterNetwork)?.ToString();
            return result;
        }

    }
}